/**
 * 
 */
package gui.text;

import java.awt.Component;

import javax.swing.JTextPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.Caret;
import javax.swing.text.Element;
import javax.swing.text.StyleConstants;

/**
 * Listens to changes in the caret. If one is found searches for a child component at the current position
 * to give focus to.
 * 
 * @author Joshua Lockerman
 * 
 */
public class FocusDownCaretListener implements CaretListener {
    
    private final JTextPane defaultEditor;
    
    /**
     * @param editor
     *            the JTextPane this Listener listens to.
     * 
     */
    public FocusDownCaretListener(JTextPane editor)
    {
        defaultEditor = editor;
    }
    
    @Override
    public void caretUpdate(CaretEvent e)
    {
        Caret caret = defaultEditor.getCaret();
        int pos = Math.min(caret.getDot(), caret.getMark());
        
        Element elem = defaultEditor.getDocument().getDefaultRootElement();
        Component c = findComponent(elem, pos);
        if(c != null) {
            c.requestFocusInWindow();
        }
    }
    
    private Component findComponent(Element elem, int pos)
    {
        Component component = null;
        boolean outOfBounds = false;
        for(int i = 0; !outOfBounds && i < elem.getElementCount(); i++) {
            if(elem.getElement(i).getStartOffset() <= pos
                    && elem.getElement(i).getEndOffset() >= pos) {
                component = findComponent(elem.getElement(i), pos);
            }
            else if(elem.getElement(i).getStartOffset() > pos
                    || elem.getElement(i).getEndOffset() < pos) {
                outOfBounds = true;
            }
        }
        if(component == null) {
            AttributeSet attributes = elem.getAttributes();
            component = (Component) attributes.getAttribute(StyleConstants.ComponentAttribute);
        }
        return component;
    }
    
}
